home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource5
/
357_01
/
cstar1.exe
/
REG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-18
|
31KB
|
1,395 lines
/*
C* -- Register allocation code.
source: reg.c
started: August 4, 1986
version:
February 20, 1986
March 7, 1989
PUBLIC DOMAIN SOFTWARE
The CSTAR program was placed in the public domain on June 15, 1991,
by its author and sole owner,
Edward K. Ream
1617 Monroe Street
Madison, WI 53711
(608) 257-0802
CSTAR may be used for any commercial or non-commercial purpose.
See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
*/
#include "cstar.h"
/*
NOTE: For the time being, get_temp creates fresh nodes
every time. Nodes have to be held through the completion of
the peephole phase, and it is NOT, repeat NOT, ok to change
them simply because gen_xxx has already been called on them!
*/
/*
AVAIL registers are not defined by the user or used as special regs.
FREE registers are registers which may be used as temporaries.
USED registers have been used since the last regs_init
such registers need to be saved and restored by the function.
*/
/* Forward declarations of functions. */
static struct node * get_bot();
static int get_free();
/* -----
#enum(1, GET_A, GET_D, GET_S)
----- */
#define GET_A 1
#define GET_D 2
#define GET_S 3
/* Define S stack, a simulation stack used to allocate registers. */
#define SS_MAX 200
extern int ss_count, ss_forks, ss_bot;
static struct node * s_stack[SS_MAX];
static int sf_stack[SS_MAX];
/* Track the AVAILABLE registers, and which of them are FREE. */
static int ga_avail [8];
static int gd_avail [8];
extern int sa_avail [8];
extern int sd_avail [8];
extern int sa_used [8];
extern int sd_used [8];
static int sa_free [8];
static int sd_free [8];
/* Keep track of the number of registers in each set. */
static int na_avail;
static int nd_avail;
extern int na_free;
extern int nd_free;
/*
Externally visible routines:
*/
void regs_clear (void);
unsigned long pd_alloc (struct type_node *t, int mode);
struct node * locn_xconst (long value);
struct node * locn_dupl (struct node *s);
struct node * locn_xdupl (struct node *s);
struct node * locn_chmod (struct node *loc, int mode);
struct node * locn_reg (int reg);
static int get_free (int sx_free[]);
struct node * get_temp (struct node * loc);
struct node * get_dtemp (void);
struct node * get_atemp (void);
void free_temp (struct node *loc);
void free_xtemp (struct node *loc1, struct node *loc2);
void force_free (int reg);
void push_scratch (void);
void free_reg (int reg);
bool alloc_reg (int reg);
void regs_init (void);
void free_all (void);
bool is_equiv (struct node *loc1, struct node *loc2);
bool is_cloc (struct node * loc);
struct node * fix_cloc (register struct node * loc);
bool is_zloc (struct node * loc);
bool is_xloc (struct node * loc);
bool is_xtloc (struct node * loc);
bool is_aloc (struct node * loc);
bool is_atloc (struct node * loc);
bool is_atreg (int reg);
bool is_dtreg (int reg);
bool is_dloc (struct node * loc);
bool is_dtloc (struct node * loc);
bool has_dtreg (struct node * loc);
bool has_atreg (struct node * loc);
bool is_storloc (struct node *p);
void ss_push (struct node * loc);
struct node * ss_pop (void);
struct node * ss_restore (void);
/*
Internal routines:
*/
static int decl_reg (struct st_node *id);
static struct node * get_bot (int reg_type, int arg);
static struct node ** find_rloc (register int reg);
/*
Deallocate the local registers
*/
void
regs_clear(void)
{
register int i;
TICK("regs_clear");
na_free = nd_free = 0;
for (i = 0; i < 8; i++) {
if (ga_avail[i]) {
na_avail++;
}
sa_avail[i] = sa_free[i] = ga_avail[i];
if (gd_avail[i]) {
nd_avail++;
}
sd_avail[i] = sd_free[i] = gd_avail[i];
sa_used[i] = sd_used[i] = FALSE;
}
na_free = na_avail;
nd_free = nd_avail;
/* NOTE: for this purpose, A6 and A7 do not show up as sa_used;
they are saved and restored independently of other regs */
}
/*
Go through an ELEMENT list and do the offsets.
See note in lint.c about folded variables. Offsets are treated as
signed longs, and that may not be good enough for fully-stuffed
or virtual memory systems.
*/
unsigned long
pd_alloc(struct type_node *t, int mode)
{
register struct type_node *t1;
register struct st_node *id;
register struct node *loc1, *loc3;
register long o, size;
register int reg;
TRACEPB("pd_alloc", printf("(%p, %d)\n", t, mode));
switch (mode) {
case 0:
/* formals */
o = 8;
break;
case 1:
/* locals */
o = 0;
break;
default:
/* all else */
o = 0;
}
size = o;
while (t != NULL) {
TRACEP("pd_alloc", printf("doing node %p\n", t));
if (!is_element(t -> t_typtok)) {
t_error("pd_alloc: internal: not ELEMENT");
break;
}
id = t -> t_parent;
if (id == NULL) {
/* currently, pure tags have no parents */
t = t -> t_list;
continue;
}
t1 = t -> t_link;
if (t1 == NULL) {
t_error("pd_alloc: internal: typeless ELEMENT");
break;
}
switch (mode) {
case 0:
/* formals */
if (t1 -> t_tsize == 1) {
/*
byte size argument treated as
interchangeable with int for
compatibility
*/
id -> st_offset = o + 1;
o += 2;
}
else {
/* word or long size argument */
id -> st_offset = o;
o += (long) t1 -> t_tsize;
}
#ifdef DEBUG
if (t1 -> t_tsize == 3 || t1 -> t_tsize > 4) {
t_error("formal has bad size");
}
#endif /* DEBUG */
if (id -> st_sclass == FORMREG_CLASS) {
if (reg = decl_reg(id)) {
TRACEP("pd_alloc", printf("formal register\n"););
loc3 = locn_reg(reg);
loc3 -> n_cltype = id -> st_type;
loc1 = locn_xconst(id -> st_offset);
loc1 -> n_reg1 = R_A6;
loc1 -> n_mode = EA_MODE;
g_2l2(X_MOVE, loc1, loc3);
}
else {
id -> st_sclass = FORMAL_CLASS;
}
}
break;
case 1:
/* locals */
switch (id -> st_sclass) {
case REGISTER_CLASS:
if (decl_reg(id)) {
id -> st_offset = 0;
break;
}
else {
id -> st_sclass = AUTO_CLASS;
}
/* FALL_THROUGH */
case AUTO_CLASS:
o -= (long) t1 -> t_tsize;
/* keep start of larger objects on even boundary */
if ((o & 1) && t1 -> t_tsize > 1) {
o--;
}
id -> st_offset = o;
break;
}
break;
case 2:
/* elements of structures */
/* keep start of larger objects on even boundary */
if ((o & 1) && t1 -> t_tsize > 1) {
if (t1 -> t_typtok == ARRAY_TYPE &&
t1 -> t_tsize == t1 -> t_tdim) {
/* don't mess with boundary for
array of bytes */
}
else {
o++;
}
}
id -> st_offset = o;
o += (long) t1 -> t_tsize;
break;
case 3:
/* elements of unions */
id -> st_offset = 0;
/* WARNING: see note above about variables without sign: */
if (t1 -> t_tsize > (unsigned long) o) {
o = t1 -> t_tsize;
}
break;
}
t = t -> t_list;
}
size -= o; /* this is the change in o */
/* WARNING: see note above about variables without sign: */
if (size < 0) {
size = -size;
}
/* WARNING: see note above about variables without sign: */
if (size > 1 && (size & 1)) {
size += 1; /* effect: treat all non-characters as being
of even size; this way something like
byte *p; p = p + sizeof(aggregate);
will work properly */
}
RETURN_ULONG("pd_alloc", (unsigned long) size);
}
/*
mark register unavailable and assign to st_node if necessary
*/
static int
decl_reg(struct st_node *id)
{
register int i, j, reg;
reg = id -> st_misc & ST_REG; /* pick up manifest reg */
TRACEPB("decl_reg", printf("reg = %d\n", reg));
if (is_areg(reg)) {
/* Seize a specific A register--even a scratch register */
i = reg_idx(reg);
sa_free[i] = sa_avail[i] = FALSE;
sa_used[i] = TRUE;
TRACEP("decl_reg", printf("take manifest %s\n", arp_tab[reg]));
if (i < A_ALLOC) {
t_2help(arp_tab[reg], " is a scratch register");
}
RETURN_INT("decl_reg", reg);
}
else if (is_dreg(reg)) {
/* Seize a specific D register. */
i = reg_idx(reg);
sd_free[i] = sd_avail[i] = FALSE;
sd_used[i] = TRUE;
TRACEP("decl_reg", printf("take manifest %s\n", arp_tab[reg]));
if (i < D_ALLOC) {
t_2help(arp_tab[reg], " is a scratch register");
}
RETURN_INT("decl_reg", reg);
}
if (id -> st_type -> t_typtok == INT_TYPE) {
/* Seize any D register among D2..D7 */
for (j = 7; j >= D_ALLOC; j--) {
if (sd_avail[j]) {
id -> st_misc |= d_reg(j) & ST_REG;
sd_avail[j] = FALSE;
sd_used[j] = TRUE;
TRACEP("decl_reg", printf("allocate reg %s\n",
arp_tab[d_reg(j)]));
RETURN_INT("decl_reg", d_reg(j));
}
}
}
else {
/* Seize any A register among A2..A5 */
for (j = 5; j >= A_ALLOC; j--) {
if (sa_avail[j]) {
id -> st_misc |= a_reg(j) & ST_REG;
sa_avail[j] = FALSE;
sa_used[j] = TRUE;
TRACEP("decl_reg", printf("allocate %s\n",
arp_tab[a_reg(j)]));
RETURN_INT("decl_reg", a_reg(j));
}
}
}
RETURN_INT("decl_reg", 0);
}
/*
Return a constant node
*/
struct node *
locn_xconst(long value)
{
TRACEPB("locn_xconst", printf("(%ld)\n", value));
RETURN_PTR("locn_xconst", new_cloc(value));
}
/*
Make a new copy of a loc_node
*/
struct node *
locn_dupl(register struct node *s)
{
register int i;
register struct node *r, *d;
r = d = /* CAST(struct node *) */ new_pnode(sizeof(struct loc_node));
TRACEPB("locn_dupl", printf("copy %p to %p\n", s, d));
i = sizeof(struct loc_node)/sizeof(int);
while (i--) {
*((int *)d)++ = *((int *)s)++;
}
RETURN_PTR("locn_dupl", r);
}
/*
Make a new copy of a loc_node if it is not marked
*/
struct node *
locn_xdupl(register struct node *s)
{
register int i;
register struct node *r, *d;
r = d = /* CAST(struct node *) */ new_pnode(sizeof(struct loc_node));
TRACEPB("locn_xdupl", printf("copy %p to %p\n", s, d));
i = sizeof(struct loc_node)/sizeof(int);
while (i--) {
*((int *)d)++ = *((int *)s)++;
}
RETURN_PTR("locn_xdupl", r);
}
/*
Change the mode of a loc_node by swapping if possible
Else by copying if marked
Else directly
It is presumed that the mode does need changing
*/
struct node *
locn_chmod(struct node *loc, int mode)
{
TRACEPB("locn_chmod", printf("(%p, %d)\n", loc, mode));
loc = locn_dupl(loc);
loc -> n_mode = (byte) mode;
RETURN_PTR("locn_chmod", loc);
}
/*
Return a loc_node corresponding to the given register
field
If the field corresponds to a temporary, do it by swapping
*/
struct node *
locn_reg(int reg)
{
TRACEPB("locn_reg", printf("(%d)\n", reg));
RETURN_PTR("locn_reg", new_rloc(reg));
}
/*
return index of free register
THIS DOES NOT CHANGE THE FREE ARRAY
*/
static int
get_free(int sx_free[])
{
register int index;
/* return lowest free register */
TRACEPB("get_free", printf("(%p)\n", sx_free));
for (index = 0; index <= 7; index++) {
if (sx_free[index]) {
RETURN_INT("get_free", index);
}
}
RETURN_INT("get_free", 0);
}
/*
Return a pointer to a temporary register compatible with loc.
*/
struct node *
get_temp(struct node * loc)
{
register struct node *p;
TRACEPB("get_temp", printf("(%p)\n", loc));
if (loc -> n_cltype -> t_typtok != INT_TYPE) {
p = get_atemp();
}
else {
p = get_dtemp();
}
p -> n_cltype = loc -> n_cltype;
/* BUG FIX: */
RETURN_PTR("get_temp", p);
}
/*
Return a pointer to a D temporary register
*/
struct node *
get_dtemp(void)
{
struct node *p;
int index;
/* Return a free D register. */
TICKB("get_dtemp");
if (nd_free) {
/* identify and take the free D register */
index = get_free(sd_free);
sd_free [index] = FALSE;
nd_free--;
p = new_rloc(d_reg(index));
sd_used [index] = TRUE; /* sd_used is NOT related to sd_free */
}
else {
/* Push the bottom D reg and return it. */
p = get_bot(GET_D, 0);
}
TRACEP("get_dtemp",
printf("return %p: %d , %d free\n", p, p -> n_reg1, nd_free));
RETURN_PTR("get_dtemp", p);
}
/*
Return a pointer to an A temporary
*/
struct node *
get_atemp(void)
{
register struct node *p;
register int index;
TICKB("get_atemp");
if (na_free) {
index = get_free(sa_free);
sa_free [index] = FALSE;
na_free--;
p = new_rloc(a_reg(index));
sa_used [index] = TRUE; /* sa_used is NOT related to sa_free */
}
else {
/* Push the bottom A reg and return it. */
p = get_bot(GET_A, 0);
}
TRACEP("get_atemp",
printf("return %p: %d , %d free\n",
p, a_reg(index), na_free));
RETURN_PTR("get_atemp", p);
}
/*
Get a temporary by "pushing" a stack node; at least one item is
always "pushed".
This is the only code that increases ss_bot. ss_bot is then
decreased only by ss_pop.
CAUTION: ss_bot is interrogated in g_2call and gen_args to determine
whether anything is on the physical stack, in order to disable the
use of nopush_loc if that is so.
Nodes below ss_bot are already "pushed" in this sense. The node
at ss_bot is examined for temporaries. If it has any, it is pushed,
and they are freed. If either temporary is of the requested
type, it is returned. Otherwise the process repeats with the new
(incremented) ss_bot.
If ss_bot is at or over the ss_forks threshold, nodes are resolved
prior to being pushed. This is intended for nodes that are to
be retrieved by ss_pop() and used directly as operands. If ss_bot
is below the ss_forks threshold, any temporary COMPONENTS are pushed
individually. These nodes MUST be retrieved by ss_restore(); their
retrieval by ss_pop() is a fatal error.
If a temporary is not found, a fatal error occurs.
GET_S is used by push_scratch() for generating code that pushes
all the temporaries
*/
static struct node *
get_bot(int reg_type, int arg)
{
register int reg, count;
register struct node *loc, *loci;
TRACEPB("get_bot",
printf("(%d, %d)\n", reg_type, arg);
printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
ss_count, ss_bot, ss_forks));
if (reg_type == GET_S) {
count = arg;
}
else {
count = ss_count;
}
while (ss_bot < count) {
loc = s_stack[ss_bot];
TRACEP("get_bot", pr_loc(loc);printf("\n"));
sf_stack[ss_bot] = 0;
if (ss_bot < ss_forks) {
/* in the forks case, save node and push components */
/* WARNING:
if there are two components, it is not
strictly necessary to save both of them.
However, it simplifies the bookkeeping
*/
if (reg = loc -> n_reg1) {
if (is_atreg(reg) || is_dtreg(reg)) {
/* mark r1 save */
sf_stack[ss_bot] |= 0x801;
loci = locn_reg(reg);
loci -> n_cltype = long_type;
g_2l1(X_MOVE, loci, push_loc);
}
if ((reg = loc -> n_reg2) &&
(is_atreg(reg) || is_dtreg(reg))
) {
/* mark r2 save */
sf_stack[ss_bot] |= 0x802;
loci = locn_reg(reg);
if (loc -> n_scflag == X2_WORD) {
loci -> n_cltype = int_type;
}
else {
loci -> n_cltype = long_type;
}
g_2l1(X_MOVE, loci, push_loc);
}
free_temp(loc);
}
}
else {
/* in the normal case, combine node to value and push */
/* caller routines will expect the value in pop_loc
if it gets pushed */
if (loc = x_sspush(loc)) {
s_stack[ss_bot] = loc;
}
}
/* return if suitable register found */
if (reg_type == GET_A && na_free) {
ss_bot++;
RETURN_PTR("get_bot", get_atemp());
}
else if (reg_type == GET_D && nd_free) {
ss_bot++;
RETURN_PTR("get_bot", get_dtemp());
}
ss_bot++;
}
if (reg_type == GET_S) {
RETURN_PTR("get_bot", NULL);
}
else {
fatal("cannot get temporary");
}
TICKX("get_bot");
}
/*
Find out whether any s_stack entry contains reg, regardless of
mode
*/
static struct node **
find_rloc(register int reg)
{
register int i, count;
register struct node **ptr, *loc;
#ifdef DEBUG
register struct node **ptr2;
#endif
TRACEPB("find_rloc", printf("(%d)\n", reg));
count = ss_count;
ptr = &s_stack[0];
i = count;
while (i > 0) {
loc = *ptr;
if (loc -> n_reg1 == reg || loc -> n_reg2 == reg) {
break;
}
ptr++;
i--;
}
if (i == 0) {
RETURN_PTR("find_rloc", NULL);
}
#ifdef DEBUG
ptr2 = ptr + 1;
i--;
while (i > 0) {
if ((*ptr2) -> n_reg1 == reg || (*ptr2) -> n_reg2 == reg) {
g_error(NULL, "duplicate instance of register in s_stack");
}
i--;
ptr++;
}
#endif /* DEBUG */
RETURN_PTR("find_rloc", ptr);
}
/*
free registers designated in loc if they are temps
that is, just mark them as free
*/
void
free_temp(register struct node *loc)
{
register int reg;
TRACEPB("free_temp", printf("(%p)\n", loc));
free_reg(loc -> n_reg1);
free_reg(loc -> n_reg2);
TICKX("free_temp");
}
/*
free registers designated in loc1 if they are temps
and are not in loc2
*/
void
free_xtemp(register struct node *loc1, register struct node *loc2)
{
register int reg;
#ifdef DEBUG
TRACEPB("free_xtemp", printf("(%p, %p)\n", loc1, loc2));
if (loc2 == NULL) {
g_error(NULL, "internal: free_xtemp: NULL exception loc");
free_temp(loc1);
RETURN_VOID("free_xtemp");
}
#endif /* DEBUG */
if (reg = loc1 -> n_reg1) {
if (reg != loc2 -> n_reg1 && reg != loc2 -> n_reg2) {
free_reg(reg);
}
if (reg = loc1 -> n_reg2) {
if (reg != loc2 -> n_reg1 && reg != loc2 -> n_reg2) {
free_reg(reg);
}
}
}
TICKX("free_xtemp");
}
/*
IF the designated register appears IN THE S_STACK, get a
temporary of the same kind, move it to the temporary, and
update the s_stack item appropriately. (Use locn_xdupl).
This does NOT free the register.
*/
void
force_free(register int reg)
{
register struct node **s_loc, *loct;
register int reg2;
TRACEPB("force_free", printf("(%d)\n", reg));
if (s_loc = find_rloc(reg)) {
/* always move long; it takes the same time, and then we
are SURE it's ok */
/* nothing available to ss_push and donate to the pool */
if (is_areg(reg)) {
loct = get_atemp();
}
else {
loct = get_dtemp();
}
loct -> n_cltype = long_type;
g_2l2(X_MOVE, locn_reg(reg), loct);
/* now alter the entry */
*s_loc = loct = locn_xdupl(*s_loc);
if (loct -> n_reg1 == reg) {
loct -> n_reg1 = loct -> n_reg1;
}
if (loct -> n_reg2 == reg) {
loct -> n_reg2 = loct -> n_reg1;
}
}
TICKX("force_free");
}
/*
going up from the bottom of the s_stack, push registers
as if doing free_temp, until such time as the scratch regs
are all pushed
*/
void
push_scratch(void)
{
register int ss_ptr, reg;
TICKB("push_scratch");
for (ss_ptr = ss_count - 1; ss_ptr >= 0; ss_ptr--) {
reg = s_stack[ss_ptr] -> n_reg1;
if (reg) {
if((is_areg(reg) && reg_idx(reg) <= ASCRATCH) ||
reg_idx(reg) <= DSCRATCH) {
break;
}
reg = s_stack[ss_ptr] -> n_reg2;
if((is_areg(reg) && reg_idx(reg) <= ASCRATCH) ||
reg_idx(reg) <= DSCRATCH) {
break;
}
}
}
if (ss_ptr < 0) {
RETURN_VOID("push_scratch");
}
(void) get_bot(GET_S, ss_ptr + 1);
TICKX("push_scratch");
}
/*
free a register if it turns out to be a temp
*/
void
free_reg(register int reg)
{
register int i;
TRACEPB("free_reg", printf("(%d)\n", reg));
if (!reg) {
RETURN_VOID("free_reg");
}
i = reg_idx(reg);
if (is_areg(reg)) {
/* Free an A register. */
if (sa_avail[i] && !sa_free[i]) {
sa_free[i] = TRUE;
na_free++;
TRACE("free_reg",
printf("free_reg: free A reg: na_free = %d\n",
na_free));
}
}
else {
/* Free a D register. */
if (sd_avail[i] && !sd_free[i]) {
sd_free[i] = TRUE;
nd_free++;
TRACE("free_reg",
printf("free_reg: free D reg: nd_free = %d\n",
nd_free));
}
}
TICKX("free_reg");
}
/*
allocate a specific register as a temp if it is available
behavior is similar to get_temp, but without a search
this is used, e.g. in sop_ternop
*/
bool
alloc_reg(register int reg)
{
register int i;
TRACEPB("alloc_reg", printf("(%d)\n", reg));
if (!reg) {
RETURN_BOOL("alloc_reg", FALSE);
}
i = reg_idx(reg);
if (is_areg(reg)) {
/* Seize an A register. */
if (sa_avail[i] && sa_free[i]) {
sa_free[i] = FALSE;
sa_used[i] = TRUE;
na_free--;
TRACE("alloc_reg",
printf("alloc_reg: seize A reg: na_free = %d\n",
na_free));
RETURN_BOOL("alloc_reg", TRUE);
}
}
else {
/* Seize a D register. */
if (sd_avail[i] && sd_free[i]) {
sd_free[i] = FALSE;
sd_used[i] = TRUE;
nd_free--;
TRACE("alloc_reg",
printf("alloc_reg: seize D reg: nd_free = %d\n",
nd_free));
RETURN_BOOL("alloc_reg", TRUE);
}
}
RETURN_BOOL("alloc_reg", FALSE);
}
void
regs_init(void)
{
int i, na_max, nd_max;
TICK("regs_init");
/* WARNING: must set this up from symbol table somehow */
na_max = 6; /* always exclude a6, a7 */
nd_max = 8;
/* set up global availabilities */
for (i = 0; i < nd_max; i++) {
gd_avail [i] = TRUE;
}
for (; i < 8; i++) {
gd_avail [i] = TRUE;
}
for (i = 0; i < na_max; i++) {
ga_avail [i] = TRUE;
}
for (; i < 6; i++) {
ga_avail [i] = TRUE;
}
for (; i < 8; i++) {
ga_avail [i] = FALSE;
}
/* set up local availabilities */
regs_clear();
/* NOTE: this better not be returned by anything since it's a push */
a0_loc = new_grloc(R_A0);
d0_loc = new_grloc(R_D0);
a6_loc = new_grloc(R_A6);
a7_loc = new_grloc(R_A7);
sr_loc = new_grloc(R_SR);
ccr_loc = new_grloc(R_CCR);
push_loc = new_grloc(R_A7);
push_loc -> n_mode = EAPRD_MODE;
nopush_loc = new_grloc(R_A7);
nopush_loc -> n_mode = EA_MODE;
pop_loc = new_grloc(R_A7);
pop_loc -> n_mode = EAPSI_MODE;
one_loc = new_grloc(0);
one_loc -> n_const = 1L;
zero_loc = new_grloc(0);
}
/*
Set all available regs to free and reset the pointers.
This should normally have no effect.
*/
void
free_all(void)
{
int i;
TRACEP("free_all",
printf("free_all entry: na_free %d, nd_free %d\n",
na_free, nd_free));
na_free = nd_free = 0;
for (i = 0; i < 8; i++) {
/* not == */
if (sa_free[i] = sa_avail[i]) {
na_free++;
}
if (sd_free[i] = sd_avail[i]) {
nd_free++;
}
}
ss_count = ss_bot = ss_forks = 0;
}
/*
Return TRUE if loc1 is essentially equal to loc2 so that
either can be used in place of the other. Type is NOT
checked and should be checked by the caller if required.
*/
bool
is_equiv(register struct node *loc1, register struct node *loc2)
{
TRACEPB("is_equiv", printf("(%p, %p)\n", loc1, loc2));
if (
loc1 -> n_mode == loc2 -> n_mode &&
loc1 -> n_cid == loc2 -> n_cid &&
loc1 -> n_const == loc2 -> n_const &&
loc1 -> n_reg1 == loc2 -> n_reg1 &&
loc1 -> n_reg2 == loc2 -> n_reg2
) {
if (loc1 -> n_reg2) {
RETURN_BOOL("is_equiv",
(loc1 -> n_scflag == loc2 -> n_scflag));
}
else {
RETURN_BOOL("is_equiv", TRUE);
}
}
RETURN_BOOL("is_equiv", FALSE);
}
/*
Return TRUE if the loc node is a constant--that is, does
not contain a register component or EA mode.
*/
bool
is_cloc(struct node * loc)
{
TRACEPB("is_cloc", printf("(%p)\n", loc));
RETURN_BOOL("is_cloc",
loc &&
loc -> n_mode == VALUE_MODE &&
loc -> n_reg1 == 0);
}
/*
If the node is not a constant, return NULL.
If the node is a global constant, return NULL.
If the node is or can be made into a pure numeric constant, do so.
Return a conditional copy of the node.
*/
struct node *
fix_cloc(register struct node * loc)
{
register int class;
TRACEPB("fix_cloc", printf("(%p)\n", loc));
if (loc -> n_reg1) {
RETURN_PTR("fix_cloc", NULL);
}
class = loc -> n_cid -> st_sclass;
if (loc -> n_cid) {
if ( is_rstack(class) || class == SUE_CLASS ) {
loc = locn_xdupl(loc);
loc -> n_const += loc -> n_cid -> st_offset;
loc -> n_cid = NULL;
}
else {
RETURN_PTR("fix_cloc", NULL);
}
}
else {
loc = locn_xdupl(loc);
}
RETURN_PTR("fix_cloc", loc);
}
/*
Return TRUE if the loc node represents absolute zero.
*/
bool
is_zloc(struct node * loc)
{
TRACEPB("is_zloc", printf("(%p)\n", loc));
RETURN_BOOL("is_zloc", loc &&
loc -> n_mode == VALUE_MODE &&
loc -> n_cid == NULL &&
loc -> n_const == 0L &&
loc -> n_reg1 == 0);
}
/*
Return TRUE if the loc node represents any A or D register
*/
bool
is_xloc(struct node * loc)
{
TRACEPB("is_xloc", printf("(%p)\n", loc));
RETURN_BOOL("is_xloc", loc &&
loc -> n_cid == 0 &&
loc -> n_mode == VALUE_MODE &&
is_xreg(loc -> n_reg1) &&
loc -> n_reg2 == 0);
}
/*
Return TRUE if the loc node represents any TEMPORARY register.
*/
bool
is_xtloc(struct node * loc)
{
TRACEPB("is_xtloc", printf("(%p)\n", loc));
RETURN_BOOL("is_xtloc", loc &&
loc -> n_cid == NULL &&
loc -> n_mode == VALUE_MODE &&
is_xreg(loc -> n_reg1) &&
loc -> n_reg2 == 0 &&
(is_dreg(loc -> n_reg1) && sd_avail[reg_idx(loc -> n_reg1)] ||
is_areg(loc -> n_reg1) && sa_avail[reg_idx(loc -> n_reg1)] ));
}
/*
Return TRUE if the loc node represents ANY A register.
*/
bool
is_aloc(struct node * loc)
{
TRACEPB("is_aloc", printf("(%p)\n", loc));
RETURN_BOOL("is_aloc", loc &&
loc -> n_cid == NULL &&
loc -> n_mode == VALUE_MODE &&
is_areg(loc -> n_reg1) &&
loc -> n_reg2 == 0);
}
/*
Return TRUE if loc node represents any A TEMPORARY register.
*/
bool
is_atloc(struct node * loc)
{
TRACEPB("is_atloc", printf("(%p)\n", loc));
RETURN_BOOL("is_atloc", loc &&
loc -> n_cid == NULL &&
loc -> n_mode == VALUE_MODE &&
is_areg(loc -> n_reg1) &&
loc -> n_reg2 == 0 &&
sa_avail[reg_idx(loc -> n_reg1)]);
}
/*
Return TRUE if designator designates any A TEMPORARY register.
*/
bool
is_atreg(int reg)
{
TRACEPB("is_atreg", printf("(%d)\n", reg));
RETURN_BOOL("is_atreg", is_areg(reg) &&
sa_avail[reg_idx(reg)]);
}
/*
Return TRUE if designator designates any D TEMPORARY register.
*/
bool
is_dtreg(int reg)
{
TRACEPB("is_dtreg", printf("(%d)\n", reg));
RETURN_BOOL("is_dtreg", is_dreg(reg) &&
sd_avail[reg_idx(reg)]);
}
/*
Return TRUE if loc node represents any D register.
*/
bool
is_dloc(struct node * loc)
{
TRACEPB("is_dloc", printf("(%p)\n", loc));
RETURN_BOOL("is_dloc", loc &&
loc -> n_cid == NULL &&
loc -> n_mode == VALUE_MODE &&
is_dreg(loc -> n_reg1) &&
loc -> n_reg2 == 0);
}
/*
Return TRUE if loc node represents any D TEMPORARY register.
*/
bool
is_dtloc(struct node * loc)
{
TRACEPB("is_dtloc", printf("(%p)\n", loc));
RETURN_BOOL("is_dtloc", loc &&
loc -> n_cid == NULL &&
loc -> n_mode == VALUE_MODE &&
is_dreg(loc -> n_reg1) &&
loc -> n_reg2 == 0 &&
sd_avail[reg_idx(loc -> n_reg1)]);
}
/*
Return register designator if loc node contains any D TEMPORARY
*/
int
has_dtreg(struct node * loc)
{
TRACEPB("has_dtreg", printf("(%p)\n", loc));
if (loc) {
if ( is_dreg(loc -> n_reg1) &&
sd_avail[reg_idx(loc -> n_reg1)] ) {
TRACEP("has_dtreg", printf("reg1: %d\n", loc -> n_reg1));
RETURN_INT("has_dtreg", loc -> n_reg1);
}
else if ( is_dreg(loc -> n_reg2) &&
sd_avail[reg_idx(loc -> n_reg2)] ) {
TRACEP("has_dtreg",
printf("reg1: %d\n", loc -> n_reg1));
RETURN_INT("has_dtreg", loc -> n_reg2);
}
}
RETURN_INT("has_dtreg", 0);
}
/*
Return register designator if loc node contains any D TEMPORARY
*/
int
has_atreg(struct node * loc)
{
TRACEPB("has_atreg", printf("(%p)\n", loc));
if (loc) {
if ( is_areg(loc -> n_reg1) &&
sa_avail[reg_idx(loc -> n_reg1)] ) {
TRACEP("has_atreg", printf("reg1: %d\n", loc -> n_reg1));
RETURN_INT("has_atreg", loc -> n_reg1);
}
else if ( is_areg(loc -> n_reg2) &&
sa_avail[reg_idx(loc -> n_reg2)] ) {
TRACEP("has_atreg", printf("reg2: %d\n", loc -> n_reg2));
RETURN_INT("has_atreg", loc -> n_reg2);
}
}
RETURN_INT("has_atreg", 0);
}
/*
Return TRUE if loc_node could be valid destination for move
*/
bool
is_storloc(struct node *p)
{
TRACEPB("is_storloc", printf("(%p)\n", p));
if (p -> n_mode == EA_MODE) {
RETURN_BOOL("is_storloc", TRUE);
}
else if (p -> n_cid || p -> n_const) {
RETURN_BOOL("is_storloc", FALSE);
}
else if (p -> n_reg1 && p -> n_reg2) {
RETURN_BOOL("is_storloc", FALSE);
}
RETURN_BOOL("is_storloc", TRUE);
}
/*
Push and pop values on the S stack.
*/
void
ss_push(struct node * loc)
{
TRACEPB("ss_push",
printf("(%p)\n", loc);
printf("%p: ", loc);
pr_loc(loc); printf("\n");
printf("new ss_count %d\n", ss_count+1));
if (ss_count >= SS_MAX) {
g_error(NULL, "code generator stack overflow");
}
else {
s_stack [ss_count++] = loc;
}
TICKX("ss_push");
}
/* pop a node off the s_stack for use in an expression */
struct node *
ss_pop(void)
{
TRACEPB("ss_pop",
printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
ss_count, ss_bot, ss_forks));
if (ss_count <= 0) {
fatal("code generator stack underflow");
}
else {
TRACEP("ss_pop", printf("new ss_count %d\n", ss_count-1));
if (--ss_count < ss_bot) {
--ss_bot;
#ifdef DEBUG
if (sf_stack[ss_bot]) {
fatal("ss_pop: internal: pops restore node");
}
#endif /* DEBUG */
}
RETURN_PTR("ss_pop", s_stack [ss_count]);
}
TICKX("ss_pop");
}
/* restore a loc_node by popping its elements off the s_stack */
struct node *
ss_restore(void)
{
register struct node *loc, *loci;
register int flag;
TRACEPB("ss_restore",
printf("entry: ss_count = %d, ss_bot = %d, ss_forks = %d\n",
ss_count, ss_bot, ss_forks));
if (ss_bot <= 0) {
fatal("ss_restore: underflow");
}
TRACEP("ss_restore", printf("new ss_bot %d\n", ss_bot-1));
--ss_bot;
loc = s_stack [ss_bot];
/* restore components of node if pushed componentwise */
flag = FALSE;
if (sf_stack[ss_bot] & 1) {
loci = locn_reg(loc -> n_reg1);
loci -> n_cltype = long_type;
g_2l2(X_MOVE, pop_loc, loci);
(void) alloc_reg(loc -> n_reg1);
flag = TRUE;
}
if (sf_stack[ss_bot] & 2) {
loci = locn_reg(loc -> n_reg2);
if (loci -> n_scflag == X2_WORD) {
loci -> n_cltype = int_type;
}
else {
loci -> n_cltype = long_type;
}
g_2l2(X_MOVE, pop_loc, loci);
(void) alloc_reg(loc -> n_reg2);
flag = TRUE;
}
sf_stack[ss_bot] = 0;
RETURN_PTR("ss_restore", flag? loc : NULL);
}